package com.sts.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sts.common.exception.BusinessException;
import com.sts.common.utils.TokenBlackList;
import com.sts.dto.request.LoginRequest;
import com.sts.dto.request.PasswordUpdateRequest;
import com.sts.dto.request.ReTokenReq;
import com.sts.dto.request.RegisterRequest;
import com.sts.dto.response.LoginResponse;
import com.sts.dto.response.ReTokenResp;
import com.sts.dto.response.UserRegisterResp;
import com.sts.dto.response.UserInfoResp;
import com.sts.entity.Role;
import com.sts.entity.User;
import com.sts.mapper.AuthMapper;
import com.sts.service.AuthService;
import com.sts.common.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 *  认证业务实现
 *      * <p>负责注册、登录、分配角色等认证相关操作。</p>
 */
@Slf4j
@Service
public class AuthServiceImpl implements AuthService {
    @Autowired
    private AuthMapper authMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private TokenBlackList tokenBlackList;

    @Override
    @Transactional(rollbackFor = Exception.class) // 关键：任何异常都回滚
    public UserRegisterResp register(RegisterRequest req) {
        log.info("[用户注册] username={}", req.getUsername());
        validateUniqueConstraints(req);          // 校验防重
        User user = createUserFromRequest(req);  // 构造实体
        authMapper.insert(user);                 // MyBatis-Plus 插入，主键自动回填
        assignCustomerRole(user);                // 分配角色
        return convertToDto(user);
    }
    private void assignCustomerRole(User user) {
        Role customerRole=authMapper.findRoleByCode("CUSTOMER");
        if (customerRole == null) {
            throw new BusinessException("系统未配置客户角色");
        }
        authMapper.insertUserRole(user.getId(), customerRole.getId());
    }
    private void validateUniqueConstraints(RegisterRequest req) {
        if (authMapper.exists(
                Wrappers.<User>lambdaQuery().eq(User::getUsername, req.getUsername()))) {
            throw new BusinessException("用户名已存在");
        }
        if (authMapper.exists(
                Wrappers.<User>lambdaQuery().eq(User::getEmail, req.getEmail()))) {
            throw new BusinessException("邮箱已存在");
        }
        if (authMapper.exists(
                Wrappers.<User>lambdaQuery().eq(User::getPhone, req.getPhone()))) {
            throw new BusinessException("手机号已存在");
        }
    }
    private User createUserFromRequest(RegisterRequest req) {
        return User.builder()
                .username(req.getUsername())
                .password(passwordEncoder.encode(req.getPassword()))
                .email(req.getEmail())
                .phone(req.getPhone())
                .realName(req.getRealName())
                .status(1)
                .deleted(0)
                .build();
    }
    private UserRegisterResp convertToDto(User user) {
        List<Role> roles = authMapper.findRolesByUserId(user.getId());
        return UserRegisterResp.builder()
                .id(user.getId())
                .username(user.getUsername())
                .email(user.getEmail())
                .phone(user.getPhone())
                .roles(roles) // 默认角色
                .status(user.getStatus())
                .build();
    }
    //登录
    @Override
    @Transactional(rollbackFor = Exception.class) // 关键：任何异常都回滚
    public LoginResponse login(LoginRequest logreq) {
        log.info("[用户登录] username={}", logreq.getUsername());
        // 1. 校验登录信息
        User user=validateLoginCredentials(logreq);
        // 2. 处理登录业务（检查状态、获取角色）
        List<Role> roles=processLoginBusiness(user);
        // 3. 生成并返回令牌
        return generateLoginResponse(user,roles);
    }
    
    private User validateLoginCredentials(LoginRequest logreq) {
        // 根据用户名查询用户
        User user =authMapper.selectOne(
                Wrappers.<User>lambdaQuery()
                        .eq(User::getUsername, logreq.getUsername())
        );
        //用户不存在或已删除
        if(user == null || user.getDeleted()==1){
            throw new BusinessException("用户名或密码错误");
        }
        //校验密码
        if(!passwordEncoder.matches(logreq.getPassword(), user.getPassword())){
            throw new BusinessException("用户名或密码错误");
        }
        return user;
    }
    private List<Role> processLoginBusiness(User user) {
        //检查用户状态
        if(user.getStatus()!=1){
            throw new BusinessException("账号已被禁用，请联系管理员");
        }
        //查询用户角色
        List<Role> roles=authMapper.findRolesByUserId(user.getId());
        if(roles.isEmpty()){
            throw new BusinessException("用户未分配角色，无法登录");
        }
        return roles;
    }

    private LoginResponse generateLoginResponse(User user, List<Role> roles) {
        // 准备JWT claims
        Map<String,Object> claims=new HashMap<>();
        claims.put("userId",user.getId());
        claims.put("username",user.getUsername());
        claims.put("roles",roles.stream().map(Role::getRoleCode).collect(Collectors.toList()));
        // 生成JWT token
        String token = jwtUtil.generateToken(claims);
        // 构建响应对象
        return LoginResponse.builder()
                .token(token)
                .tokenType("Bearer")
                .userInfo(LoginResponse.UserInfo.builder()
                        .id(user.getId())
                        .username(user.getUsername())
                        .email(user.getEmail())
                        .phone(user.getPhone())
                        .roles(roles.stream().map(Role::getRoleCode).collect(Collectors.toList()))
                        .build())
                .build();
    }
    //获取用户信息
    @Override
    @Transactional(rollbackFor = Exception.class) // 关键：任何异常都回滚
    public UserInfoResp getUserInfo(String authorization) {
        //1.校验并提取纯Token
        String token=getToken(authorization);
        //2.解析token得到userId
        Long userId=parseUserId(token);
        //3.查询并组装Dto
        return buildUserInfoResp(userId);
    }
    private String getToken(String authorization) {
        if (authorization == null || authorization.trim().isEmpty() || !authorization.startsWith("Bearer ")) {
            throw new BusinessException("非法 Authorization 头");
        }
        return authorization.substring(7);
    }

    private Long parseUserId(String token) {
        Claims claims = (Claims) jwtUtil.parseToken(token);
        return Long.valueOf(claims.get("userId").toString());
    }

    private UserInfoResp buildUserInfoResp(Long userId) {
        // 1. 查用户
        User user = authMapper.selectById(userId);
        if (user == null || user.getDeleted() == 1) {
            throw new BusinessException("用户不存在");
        }

        // 2. 查角色编码列表
        List<String> roleCodes = authMapper.findRoleCodesByUserId(userId);
        if (roleCodes.isEmpty()) {
            throw new BusinessException("用户未分配角色");
        }

        return UserInfoResp.builder()
                .id(user.getId())
                .username(user.getUsername())
                .email(user.getEmail())
                .phone(user.getPhone())
                .realName(user.getRealName())
                .roles(roleCodes)
                .build();
    }
    // 检查用户是否存在并返回User对象
    private User checkUserExist(Long userId) {
        User user = authMapper.selectById(userId);
        if(user == null || user.getDeleted() == 1){
            throw new BusinessException("用户不存在");
        }
        return user;
    }
    //刷新token
    @Override
    public ReTokenResp refresh(String reToken) {
        // 第一步：验证Refresh Token有效性
        Claims refreshClaims = validateRefreshToken(reToken);

        // 第二步：失效旧Token（包括Access Token和当前Refresh Token）
        invalidateOldTokens(refreshClaims, reToken);

        // 第三步：生成新Token对
        return generateNewTokenPair(refreshClaims);
    }

    // 第一步：验证Refresh Token有效性
    private Claims validateRefreshToken(String reToken) {
        // 1.1 检查是否在黑名单中
        if (tokenBlackList.contains(reToken)) {
            throw new BusinessException("Refresh Token 已失效，请重新登录");
        }

        // 1.2 解析Token
        Claims claims = (Claims) jwtUtil.parseToken(reToken);

        // 1.3 验证用户状态
        Long userId = Long.valueOf(claims.get("userId").toString());
        checkUserExist(userId);

        return claims;
    }

    // 第二步：失效旧Token
    private void invalidateOldTokens(Claims refreshClaims, String reToken) {
        // 2.1 失效旧的Access Token
        String oldAccessToken = refreshClaims.get("accessToken", String.class);
        if (oldAccessToken != null) {
            long remaining = jwtUtil.getRemainingSeconds(oldAccessToken);
            tokenBlackList.add(oldAccessToken, remaining);
        }

        // 2.2 失效当前使用的Refresh Token
        long refreshRemaining = jwtUtil.getRemainingSeconds(reToken);
        tokenBlackList.add(reToken, refreshRemaining);
    }

    // 第三步：生成新Token对
    private ReTokenResp generateNewTokenPair(Claims refreshClaims) {
        Long userId = Long.valueOf(refreshClaims.get("userId").toString());
        User user = authMapper.selectById(userId);

        // 3.1 生成新Access Token
        Map<String, Object> accessClaims = new HashMap<>();
        accessClaims.put("userId", user.getId());
        accessClaims.put("username", user.getUsername());
        accessClaims.put("roles", authMapper.findRoleCodesByUserId(user.getId()));
        String newAccessToken = jwtUtil.generateToken(accessClaims);

        // 3.2 生成新Refresh Token（绑定新Access Token）
        Map<String, Object> newRefreshClaims = new HashMap<>();
        newRefreshClaims.put("userId", user.getId());
        newRefreshClaims.put("accessToken", newAccessToken);
        String newRefreshToken = jwtUtil.generateToken(newRefreshClaims);

        return ReTokenResp.builder()
                .accessToken(newAccessToken)
                .refreshToken(newRefreshToken)
                .tokenType("Bearer")
                .build();
    }
    @Override
    public void logout(String authorization) {
        String token=getToken(authorization);//去掉前缀Barer
        long remaining=jwtUtil.getRemainingSeconds(token);
        tokenBlackList.add(token,remaining);//立即拉黑
    }

    @Override
    public void updatePwd(String authorization, PasswordUpdateRequest req) {
        //日志
        Long userId = parseUserId(getToken(authorization));
        log.info("[修改密码] userId={}", userId);
        //获取并校验当前用户
        String token = getToken(authorization); // 先提取纯token
        User user=currentUser(token);
        //校验旧密码并更新
        vaildateAndUpdatePwd(user,req);
        //立即拉黑Token
        blackListToken(getToken(authorization));
    }
    //校验当前用户
    private User currentUser(String token) {
        //解析获取当前token
        Long userId=parseUserId(token);
        User user=authMapper.selectById(userId);
        if(user==null || user.getDeleted()==1){
            throw new BusinessException("用户不存在");
        }
        return user;
    }
    //校验旧密码并更新
    private void vaildateAndUpdatePwd(User user, PasswordUpdateRequest req) {
        if(!passwordEncoder.matches(req.getOldPassword(),user.getPassword())){
            throw new BusinessException("旧密码错误");
        }
        user.setPassword(passwordEncoder.encode(req.getNewPassword()));
        authMapper.updateById(user);
    }
    private void blackListToken(String token) {
     long remaining=jwtUtil.getRemainingSeconds(token);
     tokenBlackList.add(token,remaining);
    }
}

